home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_stretch.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  7KB  |  313 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_stretch.c,v 1.1.2.10 2001/02/22 00:21:51 hercules Exp $";
  26. #endif
  27.  
  28. /* This a stretch blit implementation based on ideas given to me by
  29.    Tomasz Cejner - thanks! :)
  30.  
  31.    April 27, 2000 - Sam Lantinga
  32. */
  33.  
  34. #include "SDL_error.h"
  35. #include "SDL_video.h"
  36. #include "SDL_blit.h"
  37.  
  38. /* This isn't ready for general consumption yet - it should be folded
  39.    into the general blitting mechanism.
  40. */
  41.  
  42. #if (defined(WIN32) && !defined(_M_ALPHA) && !defined(_WIN32_WCE)) || \
  43.     defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
  44. #define USE_ASM_STRETCH
  45. #endif
  46.  
  47. #ifdef USE_ASM_STRETCH
  48.  
  49. #if defined(WIN32) || defined(i386)
  50. #define PREFIX16    0x66
  51. #define STORE_BYTE    0xAA
  52. #define STORE_WORD    0xAB
  53. #define LOAD_BYTE    0xAC
  54. #define LOAD_WORD    0xAD
  55. #define RETURN        0xC3
  56. #else
  57. #error Need assembly opcodes for this architecture
  58. #endif
  59.  
  60. #if defined(__ELF__) && defined(__GNUC__)
  61. extern unsigned char _copy_row[4096] __attribute__ ((alias ("copy_row")));
  62. #endif
  63. static unsigned char copy_row[4096];
  64.  
  65. static int generate_rowbytes(int src_w, int dst_w, int bpp)
  66. {
  67.     static struct {
  68.         int bpp;
  69.         int src_w;
  70.         int dst_w;
  71.     } last;
  72.  
  73.     int i;
  74.     int pos, inc;
  75.     unsigned char *eip;
  76.     unsigned char load, store;
  77.  
  78.     /* See if we need to regenerate the copy buffer */
  79.     if ( (src_w == last.src_w) &&
  80.          (dst_w == last.src_w) && (bpp == last.bpp) ) {
  81.         return(0);
  82.     }
  83.     last.bpp = bpp;
  84.     last.src_w = src_w;
  85.     last.dst_w = dst_w;
  86.  
  87.     switch (bpp) {
  88.         case 1:
  89.         load = LOAD_BYTE;
  90.         store = STORE_BYTE;
  91.         break;
  92.         case 2:
  93.         case 4:
  94.         load = LOAD_WORD;
  95.         store = STORE_WORD;
  96.         break;
  97.         default:
  98.         SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
  99.         return(-1);
  100.     }
  101.     pos = 0x10000;
  102.     inc = (src_w << 16) / dst_w;
  103.     eip = copy_row;
  104.     for ( i=0; i<dst_w; ++i ) {
  105.         while ( pos >= 0x10000L ) {
  106.             if ( bpp == 2 ) {
  107.                 *eip++ = PREFIX16;
  108.             }
  109.             *eip++ = load;
  110.             pos -= 0x10000L;
  111.         }
  112.         if ( bpp == 2 ) {
  113.             *eip++ = PREFIX16;
  114.         }
  115.         *eip++ = store;
  116.         pos += inc;
  117.     }
  118.     *eip++ = RETURN;
  119.  
  120.     /* Verify that we didn't overflow (too late) */
  121.     if ( eip > (copy_row+sizeof(copy_row)) ) {
  122.         SDL_SetError("Copy buffer overflow");
  123.         return(-1);
  124.     }
  125.     return(0);
  126. }
  127.  
  128. #else
  129.  
  130. #define DEFINE_COPY_ROW(name, type)            \
  131. void name(type *src, int src_w, type *dst, int dst_w)    \
  132. {                            \
  133.     int i;                        \
  134.     int pos, inc;                    \
  135.     type pixel = 0;                    \
  136.                             \
  137.     pos = 0x10000;                    \
  138.     inc = (src_w << 16) / dst_w;            \
  139.     for ( i=dst_w; i>0; --i ) {            \
  140.         while ( pos >= 0x10000L ) {        \
  141.             pixel = *src++;            \
  142.             pos -= 0x10000L;        \
  143.         }                    \
  144.         *dst++ = pixel;                \
  145.         pos += inc;                \
  146.     }                        \
  147. }
  148. DEFINE_COPY_ROW(copy_row1, Uint8)
  149. DEFINE_COPY_ROW(copy_row2, Uint16)
  150. DEFINE_COPY_ROW(copy_row4, Uint32)
  151.  
  152. #endif /* USE_ASM_STRETCH */
  153.  
  154. /* The ASM code doesn't handle 24-bpp stretch blits */
  155. void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
  156. {
  157.     int i;
  158.     int pos, inc;
  159.     Uint8 pixel[3];
  160.  
  161.     pos = 0x10000;
  162.     inc = (src_w << 16) / dst_w;
  163.     for ( i=dst_w; i>0; --i ) {
  164.         while ( pos >= 0x10000L ) {
  165.             pixel[0] = *src++;
  166.             pixel[1] = *src++;
  167.             pixel[2] = *src++;
  168.             pos -= 0x10000L;
  169.         }
  170.         *dst++ = pixel[0];
  171.         *dst++ = pixel[1];
  172.         *dst++ = pixel[2];
  173.         pos += inc;
  174.     }
  175. }
  176.  
  177. /* Perform a stretch blit between two surfaces of the same format.
  178.    NOTE:  This function is not safe to call from multiple threads!
  179. */
  180. int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
  181.                     SDL_Surface *dst, SDL_Rect *dstrect)
  182. {
  183.     int pos, inc;
  184.     int dst_width;
  185.     int dst_maxrow;
  186.     int src_row, dst_row;
  187.     Uint8 *srcp = NULL;
  188.     Uint8 *dstp;
  189.     SDL_Rect full_src;
  190.     SDL_Rect full_dst;
  191. #if defined(USE_ASM_STRETCH) && defined(__GNUC__)
  192.     int u1, u2;
  193. #endif
  194.     const int bpp = dst->format->BytesPerPixel;
  195.  
  196.     if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
  197.         SDL_SetError("Only works with same format surfaces");
  198.         return(-1);
  199.     }
  200.  
  201.     /* Verify the blit rectangles */
  202.     if ( srcrect ) {
  203.         if ( (srcrect->x < 0) || (srcrect->y < 0) ||
  204.              ((srcrect->x+srcrect->w) > src->w) ||
  205.              ((srcrect->y+srcrect->h) > src->h) ) {
  206.             SDL_SetError("Invalid source blit rectangle");
  207.             return(-1);
  208.         }
  209.     } else {
  210.         full_src.x = 0;
  211.         full_src.y = 0;
  212.         full_src.w = src->w;
  213.         full_src.h = src->h;
  214.         srcrect = &full_src;
  215.     }
  216.     if ( dstrect ) {
  217.         if ( (dstrect->x < 0) || (dstrect->y < 0) ||
  218.              ((dstrect->x+dstrect->w) > dst->w) ||
  219.              ((dstrect->y+dstrect->h) > dst->h) ) {
  220.             SDL_SetError("Invalid destination blit rectangle");
  221.             return(-1);
  222.         }
  223.     } else {
  224.         full_dst.x = 0;
  225.         full_dst.y = 0;
  226.         full_dst.w = dst->w;
  227.         full_dst.h = dst->h;
  228.         dstrect = &full_dst;
  229.     }
  230.  
  231.     /* Set up the data... */
  232.     pos = 0x10000;
  233.     inc = (srcrect->h << 16) / dstrect->h;
  234.     src_row = srcrect->y;
  235.     dst_row = dstrect->y;
  236.     dst_width = dstrect->w*bpp;
  237.  
  238. #ifdef USE_ASM_STRETCH
  239.     /* Write the opcodes for this stretch */
  240.     if ( (bpp != 3) &&
  241.          (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
  242.         return(-1);
  243.     }
  244. #endif
  245.  
  246.     /* Perform the stretch blit */
  247.     for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) {
  248.         dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
  249.                                     + (dstrect->x*bpp);
  250.         while ( pos >= 0x10000L ) {
  251.             srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
  252.                                         + (srcrect->x*bpp);
  253.             ++src_row;
  254.             pos -= 0x10000L;
  255.         }
  256. #ifdef USE_ASM_STRETCH
  257.         switch (bpp) {
  258.             case 3:
  259.             copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  260.             break;
  261.             default:
  262. #ifdef __GNUC__
  263.             __asm__ __volatile__ ("
  264.                 call _copy_row
  265.             "
  266.             : "=&D" (u1), "=&S" (u2)
  267.             : "0" (dstp), "1" (srcp)
  268.             : "memory" );
  269. #else
  270. #ifdef WIN32
  271.         { void *code = ©_row;
  272.             __asm {
  273.                 push edi
  274.                 push esi
  275.     
  276.                 mov edi, dstp
  277.                 mov esi, srcp
  278.                 call dword ptr code
  279.  
  280.                 pop esi
  281.                 pop edi
  282.             }
  283.         }
  284. #else
  285. #error Need inline assembly for this compiler
  286. #endif
  287. #endif /* __GNUC__ */
  288.             break;
  289.         }
  290. #else
  291.         switch (bpp) {
  292.             case 1:
  293.             copy_row1(srcp, srcrect->w, dstp, dstrect->w);
  294.             break;
  295.             case 2:
  296.             copy_row2((Uint16 *)srcp, srcrect->w,
  297.                       (Uint16 *)dstp, dstrect->w);
  298.             break;
  299.             case 3:
  300.             copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  301.             break;
  302.             case 4:
  303.             copy_row4((Uint32 *)srcp, srcrect->w,
  304.                       (Uint32 *)dstp, dstrect->w);
  305.             break;
  306.         }
  307. #endif
  308.         pos += inc;
  309.     }
  310.     return(0);
  311. }
  312.  
  313.